const renderEngine = cc.renderer.renderEngine;
const renderer = renderEngine.renderer;
const gfx = renderEngine.gfx;
const Material = renderEngine.Material;

function checkShader(shader, file) {
    if (!shader.pass || shader.pass.length===0) {
        cc.error(`can‘t find pass in shader file:${file}`);
        return false;
    }
    for (let i = 0; i < shader.pass.length; i++) {
        let pass = shader.pass[i];
        if (!pass.name || pass.name.length===0) {
            cc.error(`can‘t find pass name in shader file:${file}`);
            return false;
        }
        if (!pass.vert || pass.vert.length===0) {
            pass.vert = `
            uniform mat4 viewProj;
            uniform mat4 model;
            attribute vec3 a_position;
            attribute vec2 a_uv0;
            varying vec2 uv0;
            void main () {
                mat4 mvp;
                mvp = viewProj * model;
            
                vec4 pos = mvp * vec4(a_position, 1);
                gl_Position = pos;
                uv0 = a_uv0;
            }
            `;
        }
        if (!pass.frag || pass.frag.length===0) {
            pass.frag = `
            uniform sampler2D texture;
            varying vec2 uv0;
            void main () {
                vec4 c = texture2D(texture, uv0);
                gl_FragColor = c;
            }
            `;
        }
        if (!pass.cullMode) {
            pass.cullMode = gfx.CULL_NONE;
        }
        if (!pass.depth) {
            pass.depth = {
                depthTest: false,
                depthWrite: false
            };
        }
        if (!pass.blend) {
            pass.blend = {
                rbgBlendMode: gfx.BLEND_FUNC_ADD,
                srcRBGBlendFactor: gfx.BLEND_SRC_ALPHA,
                dstRBGBlendFactor: gfx.BLEND_ONE_MINUS_SRC_ALPHA,
                alphaBlendMode: gfx.BLEND_FUNC_ADD,
                srcAlphaBlendFactor: gfx.BLEND_SRC_ALPHA,
                dstAlphaBlendFactor: gfx.BLEND_ONE_MINUS_SRC_ALPHA
            };
        }
    }
    if (!shader.uniforms) {
        shader.uniforms = [];
    }
    if (!shader.defines) {
        shader.defines = [];
    }
    cc.game.once(cc.game.EVENT_ENGINE_INITED, function () {
        for (let i = 0; i < shader.pass.length; i++) {
            cc.renderer._forward._programLib.define(shader.pass[i].name, shader.pass[i].vert, shader.pass[i].frag, shader.defines);
        }
    });
    return true;
}

function NewMaterial (shaderFile) {
    Material.call(this, false);
    //加载shader
    let shader = require(shaderFile);
    if (!checkShader(shader, shaderFile)) {
        return;
    }
    //创建pass
    let passArr = [];
    for (let i = 0; i < shader.pass.length; i++) {
        let pass = new renderer.Pass(shader.pass[i].name);
        pass.setDepth(shader.pass[i].depth.depthTest, shader.pass[i].depth.depthWrite);
        pass.setCullMode(shader.pass[i].cullMode);
        pass.setBlend(
            shader.pass[i].blend.rbgBlendMode,
            shader.pass[i].blend.srcRBGBlendFactor, shader.pass[i].blend.dstRBGBlendFactor,
            shader.pass[i].blend.alphaBlendMode,
            shader.pass[i].blend.srcAlphaBlendFactor, shader.pass[i].blend.dstAlphaBlendFactor
        );
        passArr.push(pass);
    }
    //创建Technique
    let mainTech = new renderer.Technique(
        ['transparent'],
        shader.uniforms,
        passArr
    );
    //绑定变量
    let bind = {};
    this._texture = null;
    this._textureName = "";
    for (let i = 0; i < shader.uniforms.length; i++) {
        if (shader.uniforms[i].type===renderer.PARAM_TEXTURE_2D) {
            this._textureName = shader.uniforms[i].name;
        } else {
            this[`_${shader.uniforms[i].name}`] = shader.uniforms[i].value;
            bind[shader.uniforms[i].name] = shader.uniforms[i].value;
        }
    }
    //设定变量初值
    this._effect = this.effect = new renderer.Effect(
        [mainTech],
        bind,
        shader.defines
    );
    
    this._mainTech = mainTech;
}
cc.js.extend(NewMaterial, Material);
cc.js.mixin(NewMaterial.prototype, {
    getTexture () {
        return this._texture;
    },
    setTexture (val, flipY=false) {
        if (this._texture !== val) {
            this._texture = val;
            this._texture.update({
                // Adapt to shader
                flipY: flipY,
                // For load texture
                mipmap: false
            });
            this._effect.setProperty(this._textureName, val.getImpl());
            this._texIds[this._textureName] = val.getId();
        }
    },
    setUniform (name, value) {
        this._effect.setProperty(name, value);
    },
    setDefine (name, value) {
        this._effect.define(name, !!value);
    }

});

module.exports = NewMaterial;